package com.umeox.watch.moto.dataservice.utils;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import com.umeox.moto.common.log.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

/**
 * Created by Rambo 2020/5/20
 * Describe: 内存缓存管理类
 */
public class GuavaCacheUtil {

    /**
     * 缓存项最大数量
     */
    private static final long GUAVA_CACHE_SIZE = 65535;
    /**
     * 缓存时间：秒
     */
    private static final long GUAVA_CACHE_TIME = 20;

    /**
     * 缓存操作对象
     */
    private static Cache GLOBAL_CACHE = null;

    static {
        try {
            GLOBAL_CACHE = loadCache();
        } catch (Exception e) {
            Logger.i("初始化Guava Cache出错" + e.getMessage());
        }
    }


    /**
     * 全局缓存设置
     */
    private static Cache loadCache() {
        /*
         * maximumSize 缓存池大小，在缓存项接近该大小时，Guava开始回收旧的缓存项
         * expireAfterAccess 表示最后一次使用该缓存项多长时间后失效
         * removalListener 移除缓存项时执行的逻辑方法
         * recordStats 开启Guava Cache的统计功能
         */
        Cache cache = CacheBuilder.newBuilder()
                .maximumSize(GUAVA_CACHE_SIZE)
                .expireAfterAccess(GUAVA_CACHE_TIME, TimeUnit.SECONDS)
                .removalListener(new RemovalListener<String, Object>() {
                    @Override
                    public void onRemoval(RemovalNotification<String, Object> notification) {

                    }
                })
                .build();
        return cache;
    }


    /**
     * 设置缓存值
     *
     * @param key
     * @param value
     */
    public static void put(String key, Object value) {
        try {
            GLOBAL_CACHE.put(key, value);
            Logger.d(String.format(Locale.getDefault(), "缓存命中率：%s，新值平均加载时间：%s", getHitRate(), getAverageLoadPenalty()));
        } catch (Exception e) {
            Logger.e("设置缓存值出错" + e.getMessage());
        }
    }

    /**
     * 批量设置缓存值
     */
    public static void putAll(Map<? extends String, ?> map) {
        try {
            GLOBAL_CACHE.putAll(map);
            Logger.d(String.format(Locale.getDefault(), "缓存命中率：%s，新值平均加载时间：%s", getHitRate(), getAverageLoadPenalty()));
        } catch (Exception e) {
            Logger.e("批量设置缓存值出错" + e.getMessage());
        }
    }

    /**
     * 获取缓存值
     *
     * @param key
     * @return
     */
//    public static Object get(Object key) {
//        Object obj = null;
//        try {
//            obj = GLOBAL_CACHE.get(key);
//            Logger.d(String.format(Locale.getDefault(), "缓存命中率：%s，新值平均加载时间：%s", getHitRate(), getAverageLoadPenalty()));
//        } catch (Exception e) {
//            Logger.e("获取缓存值出错" + e.getMessage());
//        }
//        return obj;
//    }

    /**
     * 获取缓存值
     * 注：如果键不存在值，将直接返回 NULL
     *
     * @param key
     * @return
     */
    public static Object getIfPresent(String key) {
        Object obj = null;
        try {
            obj = GLOBAL_CACHE.getIfPresent(key);
            Logger.d(String.format(Locale.getDefault(), "缓存命中率：%s，新值平均加载时间：%s", getHitRate(), getAverageLoadPenalty()));
        } catch (Exception e) {
            Logger.e("获取缓存值出错" + e.getMessage());
        }
        return obj;
    }

    /**
     * 移除缓存
     *
     * @param key
     */
    public static void remove(String key) {
        try {
            GLOBAL_CACHE.invalidate(key);
            Logger.d(String.format(Locale.getDefault(), "缓存命中率：%s，新值平均加载时间：%s", getHitRate(), getAverageLoadPenalty()));
        } catch (Exception e) {
            Logger.e("移除缓存出错" + e.getMessage());
        }
    }

    /**
     * 批量移除缓存
     */
    public static void removeAll(Iterable<String> keys) {
        try {
            GLOBAL_CACHE.invalidateAll(keys);
            Logger.d(String.format(Locale.getDefault(), "缓存命中率：%s，新值平均加载时间：%s", getHitRate(), getAverageLoadPenalty()));
        } catch (Exception e) {
            Logger.e("批量移除缓存出错" + e.getMessage());
        }
    }

    /**
     * 清空所有缓存
     */
    public static void removeAll() {
        try {
            GLOBAL_CACHE.invalidateAll();
            Logger.d(String.format(Locale.getDefault(), "缓存命中率：%s，新值平均加载时间：%s", getHitRate(), getAverageLoadPenalty()));
        } catch (Exception e) {
            Logger.e("清空所有缓存出错" + e.getMessage());
        }
    }

    /**
     * 获取缓存项数量
     *
     * @return
     */
    public static long size() {
        long size = 0;
        try {
            size = GLOBAL_CACHE.size();
            Logger.d(String.format(Locale.getDefault(), "缓存命中率：%s，新值平均加载时间：%s", getHitRate(), getAverageLoadPenalty()));
        } catch (Exception e) {
            Logger.e("获取缓存项数量出错" + e.getMessage());
        }
        return size;
    }

    /**
     * 获取所有缓存项的键
     *
     * @return
     */
    public static List<String> keys() {
        List<String> list = new ArrayList<>();
        try {
            ConcurrentMap<String, Object> map = GLOBAL_CACHE.asMap();
            for (Map.Entry<String, Object> item : map.entrySet()) {
                list.add(item.getKey());
            }
            Logger.d(String.format(Locale.getDefault(), "缓存命中率：%s，新值平均加载时间：%s", getHitRate(), getAverageLoadPenalty()));
        } catch (Exception e) {
            Logger.e("获取所有缓存项的键出错" + e.getMessage());
        }
        return list;
    }

    /**
     * 缓存命中率
     *
     * @return
     */
    public static double getHitRate() {
        return GLOBAL_CACHE.stats().hitRate();
    }

    /**
     * 加载新值的平均时间，单位为纳秒
     *
     * @return
     */
    public static double getAverageLoadPenalty() {
        return GLOBAL_CACHE.stats().averageLoadPenalty();
    }

    /**
     * 缓存项被回收的总数，不包括显式清除
     *
     * @return
     */
    public static long getEvictionCount() {
        return GLOBAL_CACHE.stats().evictionCount();
    }


}
